#[cfg(not(feature = "axstd"))]
use std::sync::mpsc::{self, TryRecvError};
use std::{
    io::{self, prelude::*},
    thread,
    time::{Duration, Instant},
};

const GROUND_Y: usize = 10;
const DINO_X: usize = 5;
const INITIAL_OBSTACLE_X: usize = 40;
const WIDTH: usize = 50;
const GAME_SPEED: usize = 3; // Update game every N frames

pub fn do_dino(_args: &str) {
    println!("Chrome Dino Game");
    println!("Instructions:");
    println!("  - Press SPACE to jump over obstacles");
    println!("  - Press 'q' to quit");
    println!("  - The game runs automatically");
    println!("\nPress ENTER to start...");

    let mut stdin = io::stdin();
    let mut buf = [0u8; 1];
    let _ = stdin.read(&mut buf);

    let mut game = DinoGame::new();
    game.run();
}

#[cfg(feature = "axstd")]
struct InputSource {
    stdin: io::Stdin,
}

#[cfg(feature = "axstd")]
impl InputSource {
    fn new() -> Self {
        Self { stdin: io::stdin() }
    }

    fn poll(&mut self) -> Option<u8> {
        let mut buf = [0u8; 1];
        let mut lock = self.stdin.lock();
        match lock.read(&mut buf) {
            Ok(0) => None,
            Ok(_) => Some(buf[0]),
            Err(_) => None,
        }
    }

    fn wait_for_quit(&mut self) {
        let mut buf = [0u8; 1];
        loop {
            match self.stdin.read(&mut buf) {
                Ok(0) => thread::yield_now(),
                Ok(_) if matches!(buf[0], b'q' | b'Q') => break,
                Ok(_) => {}
                Err(_) => break,
            }
        }
    }
}

#[cfg(not(feature = "axstd"))]
struct InputSource {
    rx: mpsc::Receiver<u8>,
}

#[cfg(not(feature = "axstd"))]
impl InputSource {
    fn new() -> Self {
        let (tx, rx) = mpsc::channel();
        thread::spawn(move || {
            let mut stdin = io::stdin();
            let mut buf = [0u8; 1];
            while stdin.read(&mut buf).ok() == Some(1) {
                if tx.send(buf[0]).is_err() {
                    break;
                }
            }
        });
        Self { rx }
    }

    fn poll(&mut self) -> Option<u8> {
        match self.rx.try_recv() {
            Ok(byte) => Some(byte),
            Err(TryRecvError::Empty) => None,
            Err(TryRecvError::Disconnected) => None,
        }
    }

    fn wait_for_quit(&mut self) {
        while let Ok(byte) = self.rx.recv() {
            if matches!(byte, b'q' | b'Q') {
                break;
            }
        }
    }
}

struct DinoGame {
    dino_y: usize,
    dino_velocity: i32,
    obstacle_x: usize,
    score: u32,
    game_over: bool,
    is_jumping: bool,
    frame_count: usize,
}

impl DinoGame {
    fn new() -> Self {
        Self {
            dino_y: GROUND_Y,
            dino_velocity: 0,
            obstacle_x: INITIAL_OBSTACLE_X,
            score: 0,
            game_over: false,
            is_jumping: false,
            frame_count: 0,
        }
    }

    fn jump(&mut self) {
        if self.dino_y == GROUND_Y && !self.game_over {
            self.dino_velocity = -3;
            self.is_jumping = true;
        }
    }

    fn update(&mut self) {
        // Apply gravity
        if self.dino_y < GROUND_Y || self.dino_velocity < 0 {
            self.dino_velocity += 1;
            let new_y = (self.dino_y as i32) + self.dino_velocity;
            self.dino_y = if new_y > GROUND_Y as i32 {
                self.is_jumping = false;
                GROUND_Y
            } else {
                new_y.max(0) as usize
            };
        }

        // Move obstacle
        if self.obstacle_x > 0 {
            self.obstacle_x -= 1;
        } else {
            self.obstacle_x = WIDTH;
            self.score += 10;
        }

        // Collision detection
        if self.obstacle_x >= DINO_X - 1 && self.obstacle_x <= DINO_X + 2 {
            if self.dino_y >= GROUND_Y - 1 {
                self.game_over = true;
            }
        }
    }

    fn render(&self) {
        // Clear screen (simple version)
        print!("\x1B[2J\x1B[H");

        println!("Score: {}  (Press SPACE to jump, 'q' to quit)", self.score);
        println!();

        // Render game area
        for y in 0..=GROUND_Y + 2 {
            for x in 0..WIDTH {
                if y == GROUND_Y + 1 {
                    // Ground
                    print!("=");
                } else if x == DINO_X && y >= self.dino_y && y < self.dino_y + 2 {
                    // Dino
                    if y == self.dino_y {
                        print!("D");
                    } else {
                        print!("T");
                    }
                } else if x >= self.obstacle_x
                    && x < self.obstacle_x + 2
                    && y >= GROUND_Y - 2
                    && y <= GROUND_Y
                {
                    // Obstacle
                    print!("|");
                } else {
                    print!(" ");
                }
            }
            println!();
        }

        io::stdout().flush().unwrap();
    }

    fn run(&mut self) {
        const FRAMES_PER_RENDER: usize = 2;
        let tick_duration = Duration::from_millis(60);

        println!("\nGame started!");
        println!("Press SPACE to jump over obstacles");
        println!("Press 'q' to quit");
        println!();

        let mut input = InputSource::new();

        self.render();

        loop {
            let frame_start = Instant::now();
            let mut quit_requested = false;

            loop {
                match input.poll() {
                    Some(b' ') => self.jump(),
                    Some(b'q') | Some(b'Q') => {
                        quit_requested = true;
                        break;
                    }
                    Some(b'\r') | Some(b'\n') => {}
                    Some(_) => {}
                    None => break,
                }
            }

            if quit_requested {
                println!("\nQuitting game...");
                println!("Final Score: {}", self.score);
                io::stdout().flush().unwrap();
                break;
            }

            self.frame_count = self.frame_count.wrapping_add(1);
            if self.frame_count % GAME_SPEED == 0 {
                self.update();
            }

            if self.frame_count % FRAMES_PER_RENDER == 0 || self.game_over {
                self.render();
            }

            if self.game_over {
                println!("\nGame Over! Final Score: {}", self.score);
                println!("Press 'q' to return to shell...");
                io::stdout().flush().unwrap();

                input.wait_for_quit();
                break;
            }

            let elapsed = frame_start.elapsed();
            if elapsed < tick_duration {
                thread::sleep(tick_duration - elapsed);
            }
        }
    }
}
